package file_cleaner

import (
	"file-cleaner/internal/file_cleaner/clean_handler"
	"file-cleaner/internal/file_cleaner/config"
	"file-cleaner/internal/pkg/server"
	v1log "github.com/ClessLi/component-base/pkg/log/v1"
	"github.com/marmotedu/errors"
	"github.com/marmotedu/iam/pkg/shutdown"
	"github.com/marmotedu/iam/pkg/shutdown/shutdownmanagers/posixsignal"
	"sync"
	"time"
)

type FileCleanerServer struct {
	gs              *shutdown.GracefulShutdown
	server          *server.Server
	startTime       time.Time
	reportCompleted bool
	reportLock      *sync.Mutex
}

type preparedFileCleanerServer struct {
	*FileCleanerServer
}

func createServer(cfg *config.Config) (*FileCleanerServer, error) {
	v1log.Debug("Create File-cleaner server...")
	gs := shutdown.New()
	gs.AddShutdownManager(posixsignal.NewPosixSignalManager())

	c, err := buildConfig(cfg)
	if err != nil {
		return nil, err
	}

	v1log.Debugf("Completely config: runtime config -- %+v; query config -- %+v; clean config -- %+v; report config -- %+v", *c.Runtime, *c.Query, *c.Clean, *c.Report)

	s, err := c.Complete().NewServer()
	if err != nil {
		return nil, err
	}

	return &FileCleanerServer{
		gs:         gs,
		server:     s,
		reportLock: new(sync.Mutex),
	}, nil
}

func buildConfig(cfg *config.Config) (c *server.Config, lastErr error) {
	v1log.Debug("build config, apply all options to config")
	c = server.NewConfig()

	if lastErr = cfg.Runtime.ApplyTo(c); lastErr != nil {
		return
	}

	if lastErr = cfg.Query.ApplyTo(c); lastErr != nil {
		return
	}

	if lastErr = cfg.Clean.ApplyTo(c); lastErr != nil {
		return
	}

	return
}

func (f *FileCleanerServer) PrepareRun() preparedFileCleanerServer {
	v1log.Debug("Prepare running...")

	f.gs.AddShutdownCallback(shutdown.ShutdownFunc(func(string) error {
		v1log.Warn("Graceful shutdown...")
		// waiting for in transit clean tasks to be completed
		err := f.server.GracefulShutdown()
		if err != nil {
			v1log.Errorf(err.Error())
			return err
		}

		f.reportLock.Lock()
		defer f.reportLock.Unlock()
		if !f.reportCompleted {
			if f.startTime.IsZero() {
				return errors.New("file cleaner has not running before")
			}
			cleanResult := clean_handler.NewAggregator().Aggregate(f.server.TaskInfoCache)
			during := time.Now().Sub(f.startTime)
			f.server.Reporter.ReportFromResults(cleanResult, during)

			f.reportCompleted = true
		}

		return nil
	}))

	return preparedFileCleanerServer{f}
}

func (p preparedFileCleanerServer) Run() error {
	if err := p.gs.Start(); err != nil {
		v1log.Fatalf("%+++v", err)
	}

	p.startTime = time.Now()

	err := p.server.Start()
	if err != nil {
		return err
	}

	p.reportLock.Lock()
	defer p.reportLock.Unlock()

	if !p.reportCompleted {
		cleanResult := clean_handler.NewAggregator().Aggregate(p.server.TaskInfoCache)
		during := time.Now().Sub(p.startTime)
		p.server.Reporter.ReportFromResults(cleanResult, during)
	}

	return nil
}
